﻿// uView.cpp: 实现文件
//

#include "stdafx.h"
#include "uxMapView.h"
#include "uxMapDocument.h"
#include "uxTracker.h"

#include "uCore/uGraphicsGdiplus.h"
#include "uCore/uRect.h"
#include "uCore/uMap.h"

// uView

IMPLEMENT_DYNCREATE(uxMapView, CView)

uxMapView::uxMapView()
{
	m_pMap = NULL;
	
	m_bgColor.Set(255, 255, 255);

	m_refresh = true;// false;
	m_pBitmap = NULL;

	m_pan_offset_x = 0;
	m_pan_offset_y = 0;

	m_zoomin_f = 2.0;
	m_zoomout_f = 0.5;

	m_mapOperation = operNone;
	m_paning = false;
}

uxMapView::~uxMapView()
{
	m_pMap = NULL;
	if (m_pBitmap)
	{
		delete m_pBitmap;
		m_pBitmap = NULL;
	}
}

BEGIN_MESSAGE_MAP(uxMapView, CView)
	ON_WM_MOUSEWHEEL()
	ON_WM_MOUSEMOVE()
	ON_WM_LBUTTONDBLCLK()
	ON_WM_LBUTTONDOWN()
	ON_WM_SIZE()
	ON_WM_ERASEBKGND()
	ON_WM_LBUTTONUP()
END_MESSAGE_MAP()


// uView 绘图

void uxMapView::OnDraw(CDC* pDC)
{
	//CDocument* pDoc = GetDocument();
	uxMapDocument* pDoc = (uxMapDocument*)GetDocument();
	// TODO:  在此添加绘制代码

	m_pMap = pDoc->GetMap();

	if (!m_pMap)
	{
		DrawBackground();
	}
	else
	{
		if (m_pMap->GetLayerCount() == 0)
		{
			DrawBackground();
		}
		else
		{
			CRect viewRect;
			GetClientRect(&viewRect);

			if (m_refresh)
			{
				DrawMap(viewRect);
				m_refresh = false;
				TRACE0("----------refresh----------\n");
			}
			
			// 根据计算好的Bitmap的位置，将bitmap绘制到屏幕上
			u::Size size(viewRect.Width(), viewRect.Height());
			u::GraphicsGdiplus graphics(pDC->GetSafeHdc());
			u::MapCanvas canvas(&graphics, size, &m_viewer);

			//DrawBackground();
			DrawCachedMap(canvas, viewRect, &graphics);
			
			//DrawSelection(canvas);
		}
	}
}


// uView 诊断

#ifdef _DEBUG
void uxMapView::AssertValid() const
{
	CView::AssertValid();
}

#ifndef _WIN32_WCE
void uxMapView::Dump(CDumpContext& dc) const
{
	CView::Dump(dc);
}
#endif
#endif //_DEBUG


// uView 消息处理程序


BOOL uxMapView::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt)
{
	// TODO: Add your message handler code here and/or call default
	if (m_pMap)
	{
		if (m_pMap->GetLayerCount() > 0)
		{
			if (zDelta < 0)
			{
				//SetMapOperation(operWheelOut);
				u::Envelope extent = m_viewer.GetExtent();
				extent.Scale(m_zoomin_f);
				m_viewer.SetExtent(extent);
				m_viewer.Update();
				//Invalidate();
				Refresh(true);
			}
			else if (zDelta > 0)
			{
				//SetMapOperation(operWheelIn);
				u::Envelope extent = m_viewer.GetExtent();
				extent.Scale(m_zoomout_f);
				m_viewer.SetExtent(extent);
				m_viewer.Update();
				//Invalidate();
				Refresh(true);
			}
		}
	}

	return CView::OnMouseWheel(nFlags, zDelta, pt);
}


void uxMapView::OnMouseMove(UINT nFlags, CPoint point)
{
	// TODO: Add your message handler code here and/or call default
	//TRACE0("#############################\n");
	switch (m_mapOperation)
	{
	case operPan:
	{
		if (m_paning)
		{
			HCURSOR hCur = LoadCursor(NULL, IDC_HAND);
			::SetCursor(hCur);

			//::SetCursor(hCur);
			int cur_x = point.x;
			int cur_y = point.y;

			m_pan_offset_x = cur_x - m_dn_point.x;
			m_pan_offset_y = cur_y - m_dn_point.y;
			//DrawBackground();
			Refresh();
		}
	}
	break;
	}

	CView::OnMouseMove(nFlags, point);
}


void uxMapView::OnLButtonDblClk(UINT nFlags, CPoint point)
{
	// TODO: Add your message handler code here and/or call default

	CView::OnLButtonDblClk(nFlags, point);
}


void uxMapView::OnLButtonDown(UINT nFlags, CPoint point)
{
	// TODO: Add your message handler code here and/or call default
	switch (GetMapOperation())
	{
	case operZoomIn:
		ZoomIn(point);
		break;
	case operZoomOut:
		ZoomOut(point);
		break;
	case operPan:
		//Pan(point);
	{
		m_paning = true;
		m_dn_point = point;
		//::GetCursorPos(&dn_point);
		//::ScreenToClient(m_hWnd, &dn_point);

		HCURSOR hCur = LoadCursor(NULL, IDC_HAND);
		::SetCursor(hCur);
		m_paning = true;
	}
	break;
	case operQueryByPoint:
		//QueryByPoint(point.x, point.y);
		break;
	case operQueryByRect:
		//QueryByRect(point.x, point.y);
		break;
	case operQueryByPolygon:
		//OnQueryByPolygon(point.x, point.y);
		break;
		//case operAnalyisProfile:
		//	AnalysisProfile(point.x, point.y);
		//	break;
	}

	CView::OnLButtonDown(nFlags, point);
}


void uxMapView::OnLButtonUp(UINT nFlags, CPoint point)
{
	// TODO: 在此添加消息处理程序代码和/或调用默认值
	switch (m_mapOperation)
	{
	case operPan:
	{
		if (m_paning)
		{
			HCURSOR hCur = LoadCursor(NULL, IDC_ARROW);
			::SetCursor(hCur);

			m_pan_offset_x = 0;
			m_pan_offset_y = 0;

			m_up_point.x = point.x;
			m_up_point.y = point.y;

			double mdx, mdy, mux, muy;
			double deltaX, deltaY;

			m_viewer.ToMapPoint((int)m_dn_point.x, (int)m_dn_point.y, mdx, mdy);
			m_viewer.ToMapPoint((int)m_up_point.x, (int)m_up_point.y, mux, muy);

			deltaX = mdx - mux;
			deltaY = mdy - muy;

			double xmin, ymin, xmax, ymax;
			m_viewer.GetExtent(xmin, ymin, xmax, ymax);
			xmin += deltaX;		xmax += deltaX;
			ymin += deltaY;		ymax += deltaY;
			m_viewer.SetExtent(xmin, ymin, xmax, ymax);
			m_viewer.Update();

			// 				m_src_x +=  (up_point.x - dn_point.x);
			// 				m_src_y +=  (up_point.y - dn_point.y);

						//Repaint();
						//Invalidate(TRUE);
			Refresh(true);
		}
		m_paning = false;
	}
	break;
	}

	CView::OnLButtonUp(nFlags, point);
}


void uxMapView::OnSize(UINT nType, int cx, int cy)
{
	CView::OnSize(nType, cx, cy);

	// TODO: Add your message handler code here
	m_viewer.SetSize(cx, cy);
	if (!m_pMap)
	{
		m_viewer.SetExtent(0.0, 0.0, cx, cy);
	}
	m_viewer.Update();
	m_refresh = true;
	Invalidate(TRUE);
}

void uxMapView::Refresh(bool force/*= false*/)
{
	m_refresh = force;
	Invalidate(TRUE);
}

void uxMapView::AttachMap(u::Map* pMap)
{
	m_pMap = pMap;
}

void uxMapView::SetViewer(u::Envelope& viewer)
{
	m_viewer.SetExtent(viewer);
	m_viewer.Update();
}

u::Envelope uxMapView::GetViewer()
{
	return m_viewer.GetExtent();
}

void uxMapView::DrawBackground()
{
	CRect winRect;
	GetClientRect(&winRect);
	CBrush brush(RGB(m_bgColor.GetRed(), m_bgColor.GetGreen(), m_bgColor.GetBlue()));
	GetDC()->FillRect(winRect, &brush);

	{//////////////////////////////////////////////////////////////////////////
		CRect rect;
		GetClientRect(rect);

		CDC* pDC = GetDC();
		pDC->MoveTo(0, 0);
		pDC->LineTo(rect.Width(), rect.Height());

		u::GraphicsGdiplus g(pDC->GetSafeHdc());
		g.DrawLine(rect.Width(), 0, 0, rect.Height());
	}//////////////////////////////////////////////////////////////////////////
}

/************************************************************************/
/* Gdiplus绘笔                                                          */
/************************************************************************/
void uxMapView::DrawMap(CRect& viewRect)
{
	int width = m_viewer.GetWidth();
	int height = m_viewer.GetHeight();
	//1.绘制图片缓存
	//Bitmap bitmap(width, height);
	if (m_pBitmap != NULL)
	{
		delete m_pBitmap;
	}

	m_pBitmap = new Gdiplus::Bitmap(width, height);
	u::GraphicsGdiplus graphics(m_pBitmap);

	//GCanvas canvas(m_pBitmap, m_viewer.GetWidth(), m_viewer.GetHeight());
	u::Size size(width, height);
	u::MapCanvas canvas(&graphics, size, &m_viewer);
	canvas.Draw(m_pMap);

	m_refresh = false;
}

void uxMapView::DrawCachedMap(u::MapCanvas &canvas, CRect& viewRect, /*临时使用*/u::GraphicsGdiplus* pGraphics)
{
	if (!m_pBitmap)
	{
		return;
	}

	int bw = m_pBitmap->GetWidth();
	int bh = m_pBitmap->GetHeight();
	//根据bitmap的宽高比，计算在View宽高比变化情况下，保持bitmap宽高比不变的情况下，bitmap在屏幕上的显示范围。
	// bitmap宽高比
	double b_wh = (double)bw / (double)bh;
	// view的宽高比
	double w_wh = (double)viewRect.Width() / (double)viewRect.Height();
	int x, y, nw, nh;
	if (b_wh > w_wh)
	{
		//view变高了
		nw = viewRect.Width();
		nh = nw / b_wh;
		x = 0;
		y = (viewRect.Height() / 2) - nh / 2;
	}
	else
	{
		//view变扁了
		nh = viewRect.Height();
		nw = nh * b_wh;
		x = (viewRect.Width() / 2) - nw / 2;
		y = 0;
	}
	//计算出当前缓存图像的大小
	Gdiplus::Rect newRect(x + m_pan_offset_x, y + m_pan_offset_y, nw, nh);

	// 创建新的内存Bitmap
	u::Size size(viewRect.Width(), viewRect.Height());
	Gdiplus::Bitmap memBitmap(viewRect.Width(), viewRect.Height());
	u::GraphicsGdiplus memGraphics(&memBitmap);
	u::MapCanvas memCanvas(&memGraphics, size, &m_viewer);
	memCanvas.DrawBackground();
	memCanvas.DrawImage(m_pBitmap, newRect.GetLeft(), newRect.GetTop());

	pGraphics->DrawImage(&memBitmap, 0, 0, viewRect.Width(), viewRect.Height());

	{
		//canvas.DrawImage(m_pBitmap, newRect.GetLeft(), newRect.GetTop(), newRect.Width, newRect.Height);
		//临时调用的方法，最后要在canvas上实现。
		//pGraphics->DrawImage(m_pBitmap, newRect.GetLeft(), newRect.GetTop(), newRect.Width, newRect.Height);

		//gr.DrawImage(m_pBitmap, newRect);
	}
}

BOOL uxMapView::OnEraseBkgnd(CDC* pDC)
{
	// TODO: 在此添加消息处理程序代码和/或调用默认值

	//return CView::OnEraseBkgnd(pDC);
	return TRUE;
}


void uxMapView::OnZoomIn()
{
	SetMapOperation(operZoomIn);
}

void uxMapView::OnZoomOut()
{
	SetMapOperation(operZoomOut);
}

void uxMapView::OnPan()
{
	SetMapOperation(operPan);
}

void uxMapView::OnFullScreen()
{
	if (m_pMap)
	{
		u::Envelope& extent = m_pMap->GetExtent();
		SetViewer(extent);
		//viewer.SetExtent(extent);
		//Invalidate(TRUE);
		Refresh(true);
	}
}

void uxMapView::OnReset()
{
	SetMapOperation(operNone);
}

void uxMapView::SetMapOperation(MapOperation oper)
{
	m_mapOperation = oper;
}

MapOperation uxMapView::GetMapOperation()
{
	return m_mapOperation;
}

void uxMapView::ZoomIn(CPoint point)
{
	CDC *pDC = GetDC();
	uxTracker tracker(m_hWnd, pDC->GetSafeHdc(), &m_viewer);
	u::Envelope* pExtent = tracker.TrackRectangle(point);

	double xmin, ymin, xmax, ymax;
	m_viewer.ToMapPoint(pExtent->m_xmin, pExtent->m_ymax, xmin, ymin);
	m_viewer.ToMapPoint(pExtent->m_xmax, pExtent->m_ymin, xmax, ymax);
	pExtent->Set(xmin, ymin, xmax, ymax);

	SetViewer(*pExtent);
	//Invalidate(TRUE);
	Refresh(true);
	delete pExtent;
}

void uxMapView::ZoomOut(CPoint point)
{
	CDC *pDC = GetDC();
	uxTracker tracker(m_hWnd, pDC->GetSafeHdc(), &m_viewer);
	u::Envelope* pExtent = tracker.TrackRectangle(point);

	int sxmin, symin, sxmax, symax;
	sxmin = (int)pExtent->m_xmin;
	symin = (int)pExtent->m_ymin;
	sxmax = (int)pExtent->m_xmax;
	symax = (int)pExtent->m_ymax;

	float scale = 1.5;
	int tolerance = 5;

	int width = abs(sxmax - sxmin);
	int height = abs(symax - symin);
	if ((width < tolerance) || (height < tolerance))
	{
		scale = 1.5;
	}
	else
	{
		scale = 1.5;
	}

	int scx = (sxmax + sxmin) / 2;
	int scy = (symax + symin) / 2;

	double mcx, mcy;
	m_viewer.ToMapPoint(scx, scy, mcx, mcy);

	//double mxmin, mymin, mxmax, mymax;
	u::Envelope& current_exent = m_viewer.GetExtent();
	double mwidth = (current_exent.m_xmax - current_exent.m_xmin) / 2;
	double nhieght = (current_exent.m_ymax - current_exent.m_ymin) / 2;

	double xmin = mcx - (mwidth)* scale;
	double xmax = (mwidth)* scale + mcx;
	double ymin = mcy - (nhieght)* scale;
	double ymax = (nhieght)* scale + mcy;

	pExtent->Set(xmin, ymin, xmax, ymax);

	SetViewer(*pExtent);
	//Invalidate(TRUE);
	Refresh(true);
	delete pExtent;
}

void uxMapView::Pan(CPoint point)
{
	CDC* pDC = GetDC();
	u::Envelope *pEnvelope = NULL;

	POINT dn_point, up_point;
	dn_point = point;
	//::GetCursorPos(&dn_point);
	//::ScreenToClient(m_hWnd, &dn_point);

	HCURSOR hCur = LoadCursor(NULL, IDC_HAND);
	::SetCursor(hCur);

	MSG msg;
	while (GetMessage(&msg, m_hWnd, WM_MOUSEMOVE, WM_RBUTTONDOWN))
	{
		switch (msg.message)
		{
		case WM_MOUSEMOVE:
		{
			::SetCursor(hCur);
			int cur_x = LOWORD(msg.lParam);
			int cur_y = HIWORD(msg.lParam);

			m_pan_offset_x = cur_x - dn_point.x;
			m_pan_offset_y = cur_y - dn_point.y;
			Refresh();

			// 				up_point.x=LOWORD(msg.lParam);
			// 				up_point.y=HIWORD(msg.lParam);
			// 				
			// 				double mdx, mdy, mux, muy;
			// 				double deltaX, deltaY;
			// 				
			// 				AgDisplayTransformation* pDisplayTransform = NULL;
			// 				pDisplayTransform = m_pDisplay->DisplayTransformation();
			// 				m_viewer.ToMapPoint((int)dn_point.x, (int)dn_point.y, mdx, mdy);
			// 				m_viewer.ToMapPoint((int)up_point.x, (int)up_point.y, mux, muy);
			// 				
			// 				deltaX = mdx - mux;
			// 				deltaY = mdy - muy;
			// 				
			// 				double xmin, ymin, xmax, ymax;
			// 				m_viewer.GetView(xmin, ymin, xmax, ymax);
			// 				xmin += deltaX;		xmax += deltaX;
			// 				ymin += deltaY;		ymax += deltaY;
			// 				m_viewer.SetView(xmin, ymin, xmax, ymax);
			// 				
			// 				m_src_x +=  (up_point.x - dn_point.x);
			// 				m_src_y +=  (up_point.y - dn_point.y);
			// 
			// 				Invalidate(TRUE);

		}
		break;
		case WM_LBUTTONUP:
		{
			m_pan_offset_x = 0;
			m_pan_offset_y = 0;

			up_point.x = LOWORD(msg.lParam);
			up_point.y = HIWORD(msg.lParam);

			double mdx, mdy, mux, muy;
			double deltaX, deltaY;

			m_viewer.ToMapPoint((int)dn_point.x, (int)dn_point.y, mdx, mdy);
			m_viewer.ToMapPoint((int)up_point.x, (int)up_point.y, mux, muy);

			deltaX = mdx - mux;
			deltaY = mdy - muy;

			double xmin, ymin, xmax, ymax;
			m_viewer.GetExtent(xmin, ymin, xmax, ymax);
			xmin += deltaX;		xmax += deltaX;
			ymin += deltaY;		ymax += deltaY;
			m_viewer.SetExtent(xmin, ymin, xmax, ymax);
			m_viewer.Update();

			// 				m_src_x +=  (up_point.x - dn_point.x);
			// 				m_src_y +=  (up_point.y - dn_point.y);

			//Repaint();
			//Invalidate(TRUE);
			Refresh(true);

			HCURSOR hCur = LoadCursor(NULL, IDC_ARROW);
			::SetCursor(hCur);
			return;
		}
		}
	}
}

